Topological data scripting/es

Introducción

Aquí le explicaremos cómo controlar el Entorno de Trabajo de Pieza directamente desde el intérprete de Python de FreeCAD o desde cualquier script externo. Asegúrese de consultar la sección Guionizado y las páginas Conceptos básicos de programación en FreeCAD, si necesita más información sobre cómo funciona la programación en Python en FreeCAD. Si es nuevo en el uso de Python, le recomendamos leer primero la Introducción a Python.

Ver también

Diagrama de clase

Esta es una descripción general de las clases más importantes del módulo Pieza (Part): Unified Modeling Language (UML) (Lenguaje Unificado de Modelado, UML): Clases de Python del módulo Part

Inicio

Geometría

Los objetos geométricos son los bloques de construcción de todos los objetos topológicos:

Inicio

Topología

Los siguientes tipos de datos topológicos están disponibles:

Inicio

Ejemplo: Crear una topología simple

Hilo

Ahora crearemos una topología construyéndola a partir de una geometría más sencilla. Como caso de estudio utilizaremos una pieza como la que se ve en la imagen que consta de cuatro vértices, dos arcos y dos líneas.

Inicio

Crear geometría

Primero creamos las distintas partes geométricas de este cable. Asegurándonos de que las partes que tienen que ser conectadas más tarde comparten los mismos vértices.

Así que primero creamos los puntos:

import FreeCAD as App
import Part
V1 = App.Vector(0, 10, 0)
V2 = App.Vector(30, 10, 0)
V3 = App.Vector(30, -10, 0)
V4 = App.Vector(0, -10, 0)

Inicio

Arco

Círculo


Para cada arco necesitamos un punto de ayuda:

VC1 = App.Vector(-10, 0, 0)
C1 = Part.Arc(V1, VC1, V4)
VC2 = App.Vector(40, 0, 0)
C2 = Part.Arc(V2, VC2, V3)

Inicio

Línea

Línea


Los segmentos de línea se pueden crear a partir de dos puntos:

L1 = Part.LineSegment(V1, V2)
L2 = Part.LineSegment(V3, V4)

Inicio

Poniendo todo junto

El último paso es poner los elementos base de la geometría juntos y formar una forma topológica:

S1 = Part.Shape([C1, L1, C2, L2])

Inicio

Crear un prisma

Ahora extruir el hilo en una dirección y crear una forma 3D real:

W = Part.Wire(S1.Edges)
P = W.extrude(App.Vector(0, 0, 10))

Inicio

Mostrar todo

Part.show(P)

Inicio

Crear formas básicas

Puede crear fácilmente objetos topológicos básicos con los métodos make...() del módulo Pieza:

b = Part.makeBox(100, 100, 100)
Part.show(b)

Algunos métodos disponibles make...():

Consulte la página Part API o esta otra: autogenerated Python Part API documentation, para obtener una lista completa de los métodos disponibles del módulo Part.

Inicio

Módulos de importación

Primero necesitamos importar los módulos FreeCAD y Part para poder usar su contenido en Python:

import FreeCAD as App
import Part

Inicio

Crear un vector

Los Vectores son una de las piezas de información más importantes cuando se van a construir formas. Suelen contener tres números (pero no necesariamente siempre): las coordenadas cartesianas X, Y y Z. Se crea un vector así:

myVector = App.Vector(3, 2, 0)

Hemos creado un vector en las coordenadas X = 3, Y = 2, Z = 0. En el módulo de la pieza, los vectores se utilizan en todas partes. Las formas de la pieza también utilizan otro tipo de representación de puntos llamada Vértice que es simplemente un contenedor para un vector. Se accede al vector de un vértice así:

myVertex = myShape.Vertexes[0]
print(myVertex.Point)
> Vector (3, 2, 0)

Inicio

Crear un borde

Un borde no es más que una línea con dos vértices:

edge = Part.makeLine((0, 0, 0), (10, 0, 0))
edge.Vertexes
> [<Vertex object at 01877430>, <Vertex object at 014888E0>]

Nota: También se puede crear un borde pasando dos vectores:

vec1 = App.Vector(0, 0, 0)
vec2 = App.Vector(10, 0, 0)
line = Part.LineSegment(vec1, vec2)
edge = line.toShape()

Puedes encontrar la longitud y el centro de un borde así:

edge.Length
> 10.0
edge.CenterOfMass
> Vector (5, 0, 0)

Inicio

Poniendo la forma en la pantalla

Hasta ahora hemos creado un objeto de borde, pero no aparece en ninguna parte de la pantalla. Esto se debe a que la escena 3D de FreeCAD sólo muestra lo que tú le dices que muestre. Para ello, utilizamos este sencillo método:

Part.show(edge)

La función mostrar crea un objeto en nuestro documento de FreeCAD y le asigna nuestra forma "borde". Utilízala siempre que sea el momento de mostrar tu creación en pantalla.

Inicio

Crear un hilo

Un hilo es una línea de varias aristas y puede crearse a partir de una lista de aristas o incluso de una lista de hilos:

edge1 = Part.makeLine((0, 0, 0), (10, 0, 0))
edge2 = Part.makeLine((10, 0, 0), (10, 10, 0))
wire1 = Part.Wire([edge1, edge2]) 
edge3 = Part.makeLine((10, 10, 0), (0, 10, 0))
edge4 = Part.makeLine((0, 10, 0), (0, 0, 0))
wire2 = Part.Wire([edge3, edge4])
wire3 = Part.Wire([wire1, wire2])
wire3.Edges
> [<Edge object at 016695F8>, <Edge object at 0197AED8>, <Edge object at 01828B20>, <Edge object at 0190A788>]
Part.show(wire3)

Part.show(wire3) mostrará los 4 bordes que componen nuestro cable. Otra información útil se puede recuperar fácilmente:

wire3.Length
> 40.0
wire3.CenterOfMass
> Vector (5, 5, 0)
wire3.isClosed()
> True
wire2.isClosed()
> False

Inicio

Crear una cara

Solo serán válidas las caras creadas a partir de cables cerrados. En este ejemplo, wire3 es un cable cerrado, pero wire2 no lo es (ver más arriba):

face = Part.Face(wire3)
face.Area
> 99.99999999999999
face.CenterOfMass
> Vector (5, 5, 0)
face.Length
> 40.0
face.isValid()
> True
sface = Part.Face(wire2)
sface.isValid()
> False

Solo las caras tendrán un área definida; los cables y los bordes no.

Inicio

Crear un círculo

Se puede crear un círculo así:

circle = Part.makeCircle(10)
circle.Curve
> Circle (Radius : 10, Position : (0, 0, 0), Direction : (0, 0, 1))

Si quieres crearlo en una cierta posición y con una cierta dirección:

ccircle = Part.makeCircle(10, App.Vector(10, 0, 0), App.Vector(1, 0, 0))
ccircle.Curve
> Circle (Radius : 10, Position : (10, 0, 0), Direction : (1, 0, 0))

ccircle se creará a una distancia de 10 del origen X y estará orientado hacia afuera a lo largo del eje X. Nota: makeCircle() solo acepta App.Vector() para los parámetros de posición y normal, no tuplas. También puede crear parte del círculo especificando un ángulo inicial y un ángulo final:

from math import pi
arc1 = Part.makeCircle(10, App.Vector(0, 0, 0), App.Vector(0, 0, 1), 0, 180)
arc2 = Part.makeCircle(10, App.Vector(0, 0, 0), App.Vector(0, 0, 1), 180, 360)

Los ángulos deben proporcionarse en grados. Si tiene radianes, simplemente conviértalos usando la fórmula: grados = radians * 180/pi o usando el módulo math de Python:

import math
degrees = math.degrees(radians)

Inicio

Crear un arco a lo largo de los puntos

Lamentablemente, no existe la función makeArc(), pero sí la función Part.Arc() para crear un arco que pase por tres puntos. Esta función crea un objeto arco que une el punto inicial con el punto final a través del punto medio. Para obtener un objeto de borde, se debe llamar a la función toShape() del objeto arco, al igual que cuando se usa Part.LineSegment en lugar de Part.makeLine.

arc = Part.Arc(App.Vector(0, 0, 0), App.Vector(0, 5, 0), App.Vector(5, 5, 0))
arc
> <Arc object>
arc_edge = arc.toShape()
Part.show(arc_edge)

Arc() solo acepta App.Vector() para puntos y no para tuplas. También puede obtener un arco usando una porción de un círculo:

from math import pi
circle = Part.Circle(App.Vector(0, 0, 0), App.Vector(0, 0, 1), 10)
arc = Part.Arc(circle,0,pi)

Los arcos son bordes válidos, al igual que las líneas, por lo que también se pueden utilizar en cables.

Inicio

Crear un polígono

Un polígono es simplemente un cable con múltiples aristas rectas. La función makePolygon() toma una lista de puntos y crea un cable a través de esos puntos:

lshape_wire = Part.makePolygon([App.Vector(0, 5, 0), App.Vector(0, 0, 0), App.Vector(5, 0, 0)])

Inicio

Crear una curva de Bézier

Las curvas de Bézier se utilizan para modelar curvas suaves mediante una serie de polos (puntos) y ponderaciones opcionales. La siguiente función crea una Part.BezierCurve() a partir de una serie de puntos FreeCAD.Vector(). Nota: al obtener y establecer un polo o ponderación, los índices comienzan en 1, no en 0.

def makeBCurveEdge(Points):
   geomCurve = Part.BezierCurve()
   geomCurve.setPoles(Points)
   edge = Part.Edge(geomCurve)
   return(edge)

Inicio

Crear un plano

Un plano es una superficie rectangular plana. El método utilizado para crearlo es makePlane(length, width, [start_pnt, dir_normal]). Por defecto, start_pnt = Vector(0, 0, 0) y dir_normal = Vector(0, 0, 1). Si se utiliza: dir_normal = Vector(0, 0, 1), el plano se creará orientado en la dirección positiva del eje Z, mientras que si se utiliza: dir_normal = Vector(1, 0, 0), el plano se creará orientado en la dirección positiva del eje X.

plane = Part.makePlane(2, 2)
plane
> <Face object at 028AF990>
plane = Part.makePlane(2, 2, App.Vector(3, 0, 0), App.Vector(0, 1, 0))
plane.BoundBox
> BoundBox (3, 0, 0, 5, 0, 2)

BoundBox es un cuboide que encierra el plano con una diagonal que comienza en (3, 0, 0) y termina en (5, 0, 2). Aquí, el grosor de BoundBox a lo largo del eje Y es cero, ya que nuestra figura es totalmente plana.

Nota: makePlane() solo acepta App.Vector() para start_pnt y dir_normal y no tuplas.

Inicio

Crear una elipse

Existen varias formas de crear una elipse:

Part.Ellipse()

Crea una elipse con radio mayor de 2 y radio menor de 1 con centro en (0, 0, 0).

Part.Ellipse(Ellipse)

Crea una copia de la elipse dada

Part.Ellipse(S1, S2, Center)

Crea una elipse centrada en el punto Centro, donde el plano de la elipse está definido por Centro, S1 y S2, su eje mayor está definido por Centro y S1, su radio mayor es la distancia entre el Centro y S1, y su radio menor es la distancia entre S2 y el eje mayor.

Part.Ellipse(Center, MajorRadius, MinorRadius)

Crea una elipse con radios mayor y menor MajorRadius y MinorRadius, respectivamente, ubicada en el plano definido por el punto Center y la normal (0,0,1)

eli = Part.Ellipse(App.Vector(10, 0, 0), App.Vector(0, 5, 0), App.Vector(0, 0, 0))
Part.show(eli.toShape())

En el código anterior hemos pasado S1, S2 y Center. De forma similar a Arc, Ellipse crea un objeto elíptico, no un borde, por lo que necesitamos convertirlo en un borde usando toShape() para su visualización.

Nota: Ellipse() solo acepta App.Vector() para puntos y no para tuplas.

eli = Part.Ellipse(App.Vector(0, 0, 0), 10, 5)
Part.show(eli.toShape())

Para el constructor de la elipse anterior, hemos pasado centro, radio mayor y radio menor.

Inicio

Crear un toroide

Usando makeTorus(radius1, radius2, [pnt, dir, angle1, angle2, angle]). Por defecto, pnt = Vector(0, 0, 0), dir = Vector(0, 0, 1), angle1 = 0, angle2 = 360 y angle = 360. Consideremos un toroide como un círculo pequeño cuyo centro se desplaza a lo largo de un círculo grande de tal forma que el plano del círculo siempre es perpendicular a la trayectoria del círculo grande. Radius1 es el radio del círculo grande, radius2 es el radio del círculo pequeño, pnt es el centro del toroide y dir es la dirección normal. angle1 y angle2 son ángulos en grados para el círculo pequeño; el último parámetro angle es para hacer una sección del toro:

torus = Part.makeTorus(10, 2)

El código de arriba creará un toroide con diámetro de 20 (radio de 10) y espesor de 4 (radio del círculo pequeño de 2).

tor=Part.makeTorus(10, 5, App.Vector(0, 0, 0), App.Vector(0, 0, 1), 0, 180)

El código anterior creará una porción del toroide.

tor=Part.makeTorus(10, 5, App.Vector(0, 0, 0), App.Vector(0, 0, 1), 0, 360, 180)

El código anterior creará un semitoroide; solo se modifica el último parámetro, es decir, los ángulos restantes conservan sus valores predeterminados. Al introducir el ángulo 180, se creará un toroide de 0 a 180 grados, o sea, medio toroide.

Inicio

Crear una caja o cuboide

Usando makeBox(length, width, height, [pnt, dir]). Por defecto, pnt = Vector(0, 0, 0) y dir = Vector(0, 0, 1).

box = Part.makeBox(10, 10, 10)
len(box.Vertexes)
> 8

Inicio

Crear una esfera

Usando makeSphere(radius, [pnt, dir, angle1, angle2, angle3]). Por defecto, pnt = Vector(0, 0, 0), dir = Vector(0, 0, 1), angle1 = -90, angle2 = 90 y angle3 = 360. Angle1 y angle2 son el mínimo y máximo vertical de la esfera, angle3 es el diámetro de la esfera.

sphere = Part.makeSphere(10)
hemisphere = Part.makeSphere(10, App.Vector(0, 0, 0), App.Vector(0, 0, 1), -90, 90, 180)

Inicio

Crear un cilindro

Usando makeCylinder(radius, height, [pnt, dir, angle]). Por defecto pnt = Vector(0, 0, 0), dir = Vector(0, 0, 1) y angle = 360.

cylinder = Part.makeCylinder(5, 20)
partCylinder = Part.makeCylinder(5, 20, App.Vector(20, 0, 0), App.Vector(0, 0, 1), 180)

Inicio

Crear un cono

Using makeCone(radius1, radius2, height, [pnt, dir, angle]). By default pnt = Vector(0, 0, 0), dir = Vector(0, 0, 1) and angle = 360.

cone = Part.makeCone(10, 0, 20)
semicone = Part.makeCone(10, 0, 20, App.Vector(20, 0, 0), App.Vector(0, 0, 1), 180)

Inicio

Modificar formas

Hay varias formas de modificar figuras. Algunas son operaciones de transformación sencillas, como mover o rotar figuras; otras son más complejas, como unir o restar una figura de otra.

Inicio

Operaciones de transformación

Traslación de una forma

Trasladar es el acto de mover una figura de un lugar a otro. Cualquier figura (arista, cara, cubo, etc.) se puede trasladar de la misma manera:

myShape = Part.makeBox(2, 2, 2)
myShape.translate(App.Vector(2, 0, 0))

Esto moverá nuestra figura "myShape" 2 unidades en la dirección X.

Inicio

Rotación de una forma

Para rotar una figura, es necesario especificar el centro de rotación, el eje y el ángulo de rotación:

myShape.rotate(App.Vector(0, 0, 0),App.Vector(0, 0, 1), 180)

El código de arriba rotará la forma 180 grados alrededor del eje Z.

Inicio

Transformaciones matriciales

Una matriz es una forma muy práctica de almacenar transformaciones en el mundo 3D. En una sola matriz, se pueden establecer valores de traslación, rotación y escala que se aplicarán a un objeto. Por ejemplo:

myMat = App.Matrix()
myMat.move(App.Vector(2, 0, 0))
myMat.rotateZ(math.pi/2)

Nota: Las matrices de FreeCAD funcionan en radianes. Además, casi todas las operaciones matriciales que aceptan un vector también pueden aceptar tres números, por lo que estas dos líneas hacen lo mismo:

myMat.move(2, 0, 0)
myMat.move(App.Vector(2, 0, 0))

Una vez definida nuestra matriz, podemos aplicarla a nuestra forma. FreeCAD ofrece dos métodos para hacerlo: transformShape() y transformGeometry(). La diferencia radica en que, con el primero, se garantiza que no se producirán deformaciones (véase Escalado de una forma más abajo). Podemos aplicar nuestra transformación de la siguiente manera:

myShape.transformShape(myMat)

o

myShape.transformGeometry(myMat)

Inicio

Escalar una forma

Escalar una forma es una operación más peligrosa porque, a diferencia de la traslación o la rotación, escalar de forma no uniforme (con diferentes valores para X, Y y Z) puede modificar la estructura de la figura. Por ejemplo, escalar un círculo con un valor mayor horizontalmente que verticalmente lo transformará en una elipse, que se comporta matemáticamente de forma muy diferente. Para escalar, no podemos usar transformShape(), debemos usar transformGeometry():

myMat = App.Matrix()
myMat.scale(2, 1, 1)
myShape=myShape.transformGeometry(myMat)

Inicio

Operaciones Booleanas

Diferencia

En FreeCAD, restar una forma de otra se llama "cortar" y se hace de la siguiente manera:

cylinder = Part.makeCylinder(3, 10, App.Vector(0, 0, 0), App.Vector(1, 0, 0))
sphere = Part.makeSphere(5, App.Vector(5, 0, 0))
diff = cylinder.cut(sphere)

Inicio

Intersección

The same way, the intersection between two shapes is called "common" and is done this way:

cylinder1 = Part.makeCylinder(3, 10, App.Vector(0, 0, 0), App.Vector(1, 0, 0))
cylinder2 = Part.makeCylinder(3, 10, App.Vector(5, 0, -5), App.Vector(0, 0, 1))
common = cylinder1.common(cylinder2)

Inicio

Unión

La unión se llama "fusionar" y funciona de la misma manera:

cylinder1 = Part.makeCylinder(3, 10, App.Vector(0, 0, 0), App.Vector(1, 0, 0))
cylinder2 = Part.makeCylinder(3, 10, App.Vector(5, 0, -5), App.Vector(0, 0, 1))
fuse = cylinder1.fuse(cylinder2)

Inicio

Sección

Una "sección" es la intersección entre una figura sólida y una figura plana. Devuelve una curva de intersección, una curva compuesta formada por aristas.

cylinder1 = Part.makeCylinder(3, 10, App.Vector(0, 0, 0), App.Vector(1, 0, 0))
cylinder2 = Part.makeCylinder(3, 10, App.Vector(5, 0, -5), App.Vector(0, 0, 1))
section = cylinder1.section(cylinder2)
section.Wires
> []
section.Edges
> [<Edge object at 0D87CFE8>, <Edge object at 019564F8>, <Edge object at 0D998458>, 
 <Edge  object at 0D86DE18>, <Edge object at 0D9B8E80>, <Edge object at 012A3640>, 
 <Edge object at 0D8F4BB0>]

Inicio

Extrusión

La extrusión es el acto de "empujar" una forma plana en una dirección determinada, dando como resultado un cuerpo sólido. Piense en un círculo que se convierte en un tubo al "empujarlo hacia afuera":

circle = Part.makeCircle(10)
tube = circle.extrude(App.Vector(0, 0, 2))

Si tu círculo está hueco, obtendrás un tubo hueco. Si tu círculo es en realidad un disco con una cara rellena, obtendrás un cilindro sólido.

wire = Part.Wire(circle)
disc = Part.Face(wire)
cylinder = disc.extrude(App.Vector(0, 0, 2))

Inicio

Explorar formas

Puede explorar fácilmente la estructura de datos topológica:

import Part
b = Part.makeBox(100, 100, 100)
b.Wires
w = b.Wires[0]
w
w.Wires
w.Vertexes
Part.show(w)
w.Edges
e = w.Edges[0]
e.Vertexes
v = e.Vertexes[0]
v.Point

Al escribir las líneas anteriores en el intérprete de Python, adquirirá la comprensión de la estructura de los objetos Part. Aquí, nuestro comando makeBox() creó una forma sólida. Este sólido, como todos los sólidos Part, contiene caras. Las caras siempre contienen cables, que son listas de aristas que las delimitan. Cada cara tiene al menos un cable cerrado (puede tener más si la cara tiene un agujero). En el cable, podemos ver cada arista por separado, y dentro de cada arista, podemos ver los vértices. Las aristas rectas tienen solo dos vértices, obviamente.

Inicio

Análisis de aristas

En el caso de una arista, que es una curva arbitraria, lo más probable es que desee realizar una discretización. En FreeCAD, las aristas se parametrizan por su longitud. Esto significa que puede recorrer una arista/curva a lo largo de su longitud:

import Part
box = Part.makeBox(100, 100, 100)
anEdge = box.Edges[0]
print(anEdge.Length)

Ahora puede acceder a muchas propiedades de la arista utilizando su longitud como posición. Esto significa que si esta mide 100 mm, la posición inicial es 0 y la posición final es 100.

anEdge.tangentAt(0.0)          # tangent direction at the beginning
anEdge.valueAt(0.0)            # Point at the beginning
anEdge.valueAt(100.0)          # Point at the end of the edge
anEdge.derivative1At(50.0)     # first derivative of the curve in the middle
anEdge.derivative2At(50.0)     # second derivative of the curve in the middle
anEdge.derivative3At(50.0)     # third derivative of the curve in the middle
anEdge.centerOfCurvatureAt(50) # center of the curvature for that position
anEdge.curvatureAt(50.0)       # the curvature
anEdge.normalAt(50)            # normal vector at that position (if defined)

Inicio

Usando la selección

A continuación, veremos cómo podemos utilizar una selección realizada por el usuario en el visor. En primer lugar, creamos un cuadro y lo mostramos en el visor.

import Part
Part.show(Part.makeBox(100, 100, 100))
Gui.SendMsgToActiveView("ViewFit")

Ahora seleccione algunas caras o aristas. Con este script puede iterar sobre todos los objetos seleccionados y sus subelementos:

for o in Gui.Selection.getSelectionEx():
    print(o.ObjectName)
    for s in o.SubElementNames:
        print("name: ", s)
        for s in o.SubObjects:
            print("object: ", s)

Selecciona algunas aristas y este archivo de guión calculará la longitud:

length = 0.0
for o in Gui.Selection.getSelectionEx():
    for s in o.SubObjects:
        length += s.Length

print("Length of the selected edges: ", length)

Inicio

Ejemplo: La botella OCC

Un ejemplo típico, que se encuentra en la página web de tecnología OpenCasCade [1], es cómo construir una botella. Este también es un buen ejercicio para FreeCAD. De hecho, si sigue nuestro ejemplo a continuación y la página de OCC simultáneamente, verá lo bien que se implementan las estructuras de OCC en FreeCAD. El script está incluido en la instalación de FreeCAD (dentro de la carpeta Mod/Part) y se puede llamar desde el intérprete de Python escribiendo:

import Part
import MakeBottle
bottle = MakeBottle.makeBottle()
Part.show(bottle)

Inicio

El guión

Para este tutorial, utilizaremos una versión reducida del script. En esta versión, la botella no estará ahuecada y el cuello no tendrá rosca.

import FreeCAD as App
import Part, math

def makeBottleTut(myWidth = 50.0, myHeight = 70.0, myThickness = 30.0):
    aPnt1=App.Vector(-myWidth / 2., 0, 0)
    aPnt2=App.Vector(-myWidth / 2., -myThickness / 4., 0)
    aPnt3=App.Vector(0, -myThickness / 2., 0)
    aPnt4=App.Vector(myWidth / 2., -myThickness / 4., 0)
    aPnt5=App.Vector(myWidth / 2., 0, 0)

    aArcOfCircle = Part.Arc(aPnt2, aPnt3, aPnt4)
    aSegment1=Part.LineSegment(aPnt1, aPnt2)
    aSegment2=Part.LineSegment(aPnt4, aPnt5)

    aEdge1=aSegment1.toShape()
    aEdge2=aArcOfCircle.toShape()
    aEdge3=aSegment2.toShape()
    aWire=Part.Wire([aEdge1, aEdge2, aEdge3])

    aTrsf=App.Matrix()
    aTrsf.rotateZ(math.pi) # rotate around the z-axis

    aMirroredWire=aWire.copy()
    aMirroredWire.transformShape(aTrsf)
    myWireProfile=Part.Wire([aWire, aMirroredWire])

    myFaceProfile=Part.Face(myWireProfile)
    aPrismVec=App.Vector(0, 0, myHeight)
    myBody=myFaceProfile.extrude(aPrismVec)

    myBody=myBody.makeFillet(myThickness / 12.0, myBody.Edges)

    neckLocation=App.Vector(0, 0, myHeight)
    neckNormal=App.Vector(0, 0, 1)

    myNeckRadius = myThickness / 4.
    myNeckHeight = myHeight / 10.
    myNeck = Part.makeCylinder(myNeckRadius, myNeckHeight, neckLocation, neckNormal)
    myBody = myBody.fuse(myNeck)

    return myBody

el = makeBottleTut()
Part.show(el)

Inicio

Explicación detallada

import FreeCAD as App
import Part, math

Por supuesto, necesitaremos los módulos FreeCAD e Part.

def makeBottleTut(myWidth = 50.0, myHeight = 70.0, myThickness = 30.0):
    aPnt1=App.Vector(-myWidth / 2., 0, 0)
    aPnt2=App.Vector(-myWidth / 2., -myThickness / 4., 0)
    aPnt3=App.Vector(0, -myThickness / 2., 0)
    aPnt4=App.Vector(myWidth / 2., -myThickness / 4., 0)
    aPnt5=App.Vector(myWidth / 2., 0, 0)

Aquí definimos nuestra función makeBottleTut. Esta función puede llamarse sin argumentos, como hicimos anteriormente, en cuyo caso se usarán los valores predeterminados para el ancho, la altura y el grosor. A continuación, definimos un par de puntos que se usarán para construir nuestro perfil base.

...
    aArcOfCircle = Part.Arc(aPnt2, aPnt3, aPnt4)
    aSegment1=Part.LineSegment(aPnt1, aPnt2)
    aSegment2=Part.LineSegment(aPnt4, aPnt5)

Aquí definimos la geometría: un arco, formado por tres puntos, y dos segmentos de línea, formados por dos puntos.

...
    aEdge1=aSegment1.toShape()
    aEdge2=aArcOfCircle.toShape()
    aEdge3=aSegment2.toShape()
    aWire=Part.Wire([aEdge1, aEdge2, aEdge3])

¿Recuerda la diferencia entre geometría y figuras? Aquí construimos figuras a partir de nuestra geometría básica. Tres aristas (rectas o curvas), y luego un alambre formado por esas tres aristas.

...
    aTrsf=App.Matrix()
    aTrsf.rotateZ(math.pi) # rotate around the z-axis

    aMirroredWire=aWire.copy()
    aMirroredWire.transformShape(aTrsf)
    myWireProfile=Part.Wire([aWire, aMirroredWire])

Hasta ahora solo hemos construido la mitad del perfil. En lugar de construir el perfil completo de la misma manera, podemos simplemente reflejar lo que hicimos y unir ambas mitades. Primero creamos una matriz. Una matriz es una forma muy común de aplicar transformaciones a objetos en el mundo 3D, ya que puede contener en una sola estructura todas las transformaciones básicas que pueden experimentar los objetos 3D (mover, rotar y escalar). Después de crear la matriz, la reflejamos, luego creamos una copia de nuestro alambre y le aplicamos la matriz de transformación. Ahora tenemos dos alambres, y podemos crear un tercer alambre a partir de ellos, ya que los alambres son en realidad listas de aristas.

...
    myFaceProfile=Part.Face(myWireProfile)
    aPrismVec=App.Vector(0, 0, myHeight)
    myBody=myFaceProfile.extrude(aPrismVec)

    myBody=myBody.makeFillet(myThickness / 12.0, myBody.Edges)

Ahora que tenemos un alambre cerrado, podemos convertirlo en una cara. Una vez que tenemos una cara, podemos extruirla. Al hacerlo, creamos un sólido. Luego, le aplicamos un pequeño redondeo a nuestro objeto porque nos importa el buen diseño, ¿verdad?

...
    neckLocation=App.Vector(0, 0, myHeight)
    neckNormal=App.Vector(0, 0, 1)

    myNeckRadius = myThickness / 4.
    myNeckHeight = myHeight / 10.
    myNeck = Part.makeCylinder(myNeckRadius, myNeckHeight, neckLocation, neckNormal)

En este punto, el cuerpo de nuestra botella está hecho, pero aún necesitamos crear el cuello. Así que creamos un nuevo sólido, con forma de cilindro.

...
    myBody = myBody.fuse(myNeck)

El mecanismo de fusión es muy potente. Se encargará de pegar lo que sea necesario y de retirar las piezas que deban retirarse.

...
    return myBody

Luego, devolvemos nuestra parte sólida como resultado de nuestra función.

el = makeBottleTut()
Part.show(el)

Finalmente, llamamos a la función para crear la pieza y luego hacerla visible.

Inicio

Ejemplo: Caja perforada

Aquí tiene un ejemplo completo de cómo construir una caja perforada.

La construcción se realiza lado por lado. Una vez terminado el cubo, se ahueca cortando un cilindro a través de él.

import FreeCAD as App
import Part, math

size = 10
poly = Part.makePolygon([(0, 0, 0), (size, 0, 0), (size, 0, size), (0, 0, size), (0, 0, 0)])

face1 = Part.Face(poly)
face2 = Part.Face(poly)
face3 = Part.Face(poly)
face4 = Part.Face(poly)
face5 = Part.Face(poly)
face6 = Part.Face(poly)
     
myMat = App.Matrix()

myMat.rotateZ(math.pi / 2)
face2.transformShape(myMat)
face2.translate(App.Vector(size, 0, 0))

myMat.rotateZ(math.pi / 2)
face3.transformShape(myMat)
face3.translate(App.Vector(size, size, 0))

myMat.rotateZ(math.pi / 2)
face4.transformShape(myMat)
face4.translate(App.Vector(0, size, 0))

myMat = App.Matrix()

myMat.rotateX(-math.pi / 2)
face5.transformShape(myMat)

face6.transformShape(myMat)               
face6.translate(App.Vector(0, 0, size))

myShell = Part.makeShell([face1, face2, face3, face4, face5, face6])   
mySolid = Part.makeSolid(myShell)

myCyl = Part.makeCylinder(2, 20)
myCyl.translate(App.Vector(size / 2, size / 2, 0))

cut_part = mySolid.cut(myCyl)

Part.show(cut_part)

Inicio

Cargando y guardando

Hay varias maneras de guardar su trabajo. Puede guarda su documento de FreeCAD, por supuesto, pero también puede guardar objetos Part directamente en formatos CAD comunes, como BREP, IGS, STEP y STL.

Guardar una forma en un archivo es fácil. Hay dos métodos: exportBrep(), exportIges(), exportStep() e exportStl(), disponibles para todos los objetos de forma. Entonces, haciendo:

import Part
s = Part.makeBox(10, 10, 10)
s.exportStep("test.stp")

Guardará nuestra caja en un archivo STEP. Para cargar un archivo BREP, IGES o STEP:

import Part
s = Part.Shape()
s.read("test.stp")

Para convertir un archivo STEP a un archivo IGS:

import Part
 s = Part.Shape()
 s.read("file.stp")       # incoming file igs, stp, stl, brep
 s.exportIges("file.igs") # outbound file igs

Inicio